package com.xjc.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.lang.reflect.Method;

/**
 * @author:谢君臣
 * @Date:2021/8/11-13:46
 * @version:1.0
 * @function:
 * execution：用于匹配方法执行的连接点
 * within：用于匹配指定类型内的方法执行
 * this：用于匹配当前AOP代理对象类型的执行方法；注意是AOP代理对象的类型匹配，这样就可能包括引入接口也* 类型匹配
 * target：用于匹配当前目标对象类型的执行方法；注意是目标对象的类型匹配，这样就不包括引入接口也类型匹配
 * args：用于匹配当前执行的方法传入的参数为指定类型的执行方法
 * @within：用于匹配所以持有指定注解类型内的方法
 * @target：用于匹配当前目标对象类型的执行方法，其中目标对象持有指定的注解
 * @args：用于匹配当前执行的方法传入的参数持有指定注解的执行
 * @annotation：用于匹配当前执行方法持有指定注解的方法
 * bean：Spring AOP扩展的，AspectJ没有对于指示符，用于匹配特定名称的Bean对象的执行方法
 * 10种标签组成了12种用法
 */

@Component
@Aspect
public class TransactionAdvice {

    private Logger logger = LoggerFactory.getLogger("TransactionAdvice层日志");
    @Autowired
    private DataSourceTransactionManager transactionManager;

    //定义切点 方法拦截
    @Pointcut("execution(* com.xjc.controller.PersonController.*(..))")
    public void advicePoint() { }
    // 注解拦截
    @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
    public void annotationAdvance(){}

    @Before("advicePoint()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        System.out.println("dsasdf");
    }

    @Around(value = "advicePoint()")
    public Object doAround(ProceedingJoinPoint joinPoint){
        logger.info("环绕增强");
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        boolean b = method.isAnnotationPresent(Transactional.class);
        if (b){
            DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
            definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus transaction = transactionManager.getTransaction(definition);
            try {
                Object proceed = joinPoint.proceed();
                logger.info("方法执行后");
                transactionManager.commit(transaction);
                return proceed;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                transactionManager.rollback(transaction);
            }
        }
        return "rollback";
    }
}
